﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition.Primitives;
using System.ComponentModel.Composition;

namespace FluentMef
{
    sealed class FluentComposablePart<T> : ComposablePart
    {
        object _lock;
        readonly ComposablePartDefinition _definition;
        readonly Dictionary<FluentImportDefinition, object> _importValues = new Dictionary<FluentImportDefinition, object>();
        Lazy<T> _lazy;

        public FluentComposablePart(Func<T> construct, ComposablePartDefinition definition) : this((imports) => construct(), definition)
        {
        }

        public FluentComposablePart(Func<Dictionary<FluentImportDefinition, object>, T> construct, ComposablePartDefinition definition)
        {
            _definition = definition;
            _lazy = new Lazy<T>(() => construct(_importValues));
        }

        public override IEnumerable<ExportDefinition> ExportDefinitions { get { return _definition.ExportDefinitions; } }
        public override IEnumerable<ImportDefinition> ImportDefinitions { get { return _definition.ImportDefinitions; } }
        
        public override object GetExportedValue(ExportDefinition definition)
        {
            if (definition != _definition.ExportDefinitions.First()) throw new InvalidOperationException();

            var val = _lazy.Value;

            if (_importValues.Count > 0)
            {
                var props = from kvp in _importValues
                            where kvp.Key is PropertyFluentImportDefinition
                            select kvp;

                foreach (var kvp in props)
                {
                    ((PropertyFluentImportDefinition)kvp.Key).ImportMember.SetValue(val, ((Export)kvp.Value).Value, null);
                }
            }

            return val;
        }

        public override void SetImport(ImportDefinition definition, IEnumerable<Export> exports)
        {
            SetImport((FluentImportDefinition)definition, exports);            
        }

        private void SetImport(FluentImportDefinition definition, IEnumerable<Export> exports)
        {
            if (definition.Cardinality == ImportCardinality.ZeroOrMore)
            {
                throw new NotImplementedException();
            }

            if (exports.Skip(1).Any()) throw new ImportCardinalityMismatchException();

            _importValues.Add(definition, definition.Cardinality == ImportCardinality.ExactlyOne ? exports.First() : exports.FirstOrDefault());

            //TODO: handle two matching a one...
        }
    }
}
